import Tkinter
import tkFileDialog
import tkMessageBox as tkMB

from os import sep as OS_SEP

import trapbox

from shore import *  # Imports time


WG = Tkinter.Frame, Tkinter.Label, Tkinter.Entry, Tkinter.Button
F, L, E, B = WG
LB = Tkinter.Listbox


class GUI:
    """
    """
    def __init__(self, master, caliper_ctrl):
        """
        """
        self.destroy = master.destroy
        self.frames, self.labels, self.boxes, self.buttons = [{} for wg in WG]
        self.sub_frames = {}
        self.frame_names = ('info', 'factor', 'wla', 'total_area', 'buttons')
        self.label_names = {'wla': (leaf_n,) + wla}
        self.entry_names = {'wla': (leaf_n,) + wla}
        self.sub_frame_names = {'wla': (leaf_n,) + wla}
        self.caliper_ctrl = caliper_ctrl
        self.sensors = caliper_ctrl.sensors
        self.log_file_handle = None
        # Create the base frames which will be containers for the
        # main frames (see __create_main_frames)
        self.frames['controls'] = F(master)
        self.frames['controls'].pack(side='left', fill='both', expand=True)
        #self.frames['mlist'] = F(master)
        #self.frames['mlist'].pack(side='left', fill='both', expand=True)
        #self.mlist = LB(self.frames['mlist'], width=27, bg='white')
        #self.mlist.pack(fill='both', expand=True)
        # Create sensors and various string variables
        self.__create_sensors_and_infodisp()
        # Create main frames to use as containers for widgets
        self.__create_main_frames(self.frames['controls'])
        self.__create_sub_frames()
        # Populate frames
        self.__populate__correction_factor__frame()
        self.__populate_wla_sensors_frame()
        self.__populate_info_frame()
        self.__populate_display_frame()
        self.__populate_main_buttons_frame()
        # Miscelaneous objects:
        self.file_dialog_opts = {'filetypes':
                                    [('Comma-separated values', 'csv'),
                                     ('All files', '.*')],
                                 'defaultextension':
                                    '.csv'}

    def __create_sensors_and_infodisp(self):
        for s in self.sensors:
            self.sensors[s] = Tkinter.StringVar()
        self.area_correction_factor = Tkinter.StringVar()
        self.area_factor_lock = Tkinter.StringVar()
        self.area_factor_lock.set('Lock')
        self.log_file = Tkinter.StringVar()
        self.log_file.set('Current file: %s' % self.__get_log_name())

    def __create_main_frames(self, parent):
        # Create and pack the main frames to use as containers
        for f in self.frame_names:
            self.frames[f] = F(parent)
            self.frames[f].pack(fill='both', expand=True)

    def __create_sub_frames(self):
        # Create and pack any frames within the previous frames
        # to use as containers for horizontal layout
        for sf in self.sub_frame_names:
            self.sub_frames[sf] = {}
        for f in self.frame_names:
            if f in self.sub_frame_names:
                for sf in self.sub_frame_names[f]:
                    self.sub_frames[f][sf] = F(self.frames[f])
                    self.sub_frames[f][sf].pack(side='left', expand=True)

    def __populate__correction_factor__frame(self):
        f = 'factor'
        pf = self.frames[f]  # pf: parent frame 'factor'
        position_r = {'side': 'right', 'anchor': 'e'}
        self.labels[f] = L(pf, anchor='e', text='Area correction factor:')
        self.boxes[f] = E(pf, width=6, bg='white', justify='right',
                          textvariable=self.area_correction_factor)
        self.buttons[f] = B(pf, width=7,
                            textvariable=self.area_factor_lock,
                            command=self._grab_area_factor)
        self.buttons[f].pack(padx=5, pady=20, **position_r)
        self.boxes[f].pack(**position_r)
        self.labels[f].pack(**position_r)

    def __populate_wla_sensors_frame(self):
        # Place the labels in the sub frames w, l, and a,
        # as well as the entry boxes that indicate the current reading
        sf_w = self.sub_frames[jwla]  # sf_w: sub_frames in frame 'wla'
        self.labels[jwla], self.boxes[jwla] = {}, {}
        for l, t in zip((leaf_n,) + wla, ('Leaf', 'Width', 'Length', 'Area')):
            # for label, text in...
            self.labels[jwla][l] = L(sf_w[l], text=t)
            self.labels[jwla][l].pack()
            self.boxes[jwla][l] = E(sf_w[l], width=6, justify='right',
                                 font=('fixed', 20),
                                 textvariable=self.sensors[l])
            self.boxes[jwla][l].pack(padx=5, pady=5)

    def __populate_info_frame(self):
        labels_inf_txt = 'CLAMS: Caliper-assisted\n' \
                         'Leaf Area Measuring System'
        self.labels['info'] = L(self.frames['info'], justify='left',
                                anchor='w',
                                text=labels_inf_txt)
        self.labels['info'].pack(fill='both', expand=True)
        self.labels['file'] = L(self.frames['info'], justify='left',
                                anchor='w',
                                textvariable=self.log_file)
        self.labels['file'].pack(fill='both', expand=True)

    def __populate_display_frame(self):
        ta = 'total_area'
        labels_ta_txt = '\nT o t a l   A r e a   ( c m \xc2\xb2 )'
        self.labels[ta] = L(self.frames[ta], justify='left', anchor='w',
                            text=labels_ta_txt)
        self.labels[ta].pack()
        self.display = L(self.frames[ta], bg='green', font=('helvetica', 40),
                         textvariable=self.sensors[A])
        self.display.pack(fill='both', padx=10, pady=10)

    def __populate_main_buttons_frame(self):
        bf = self.frames['buttons']
        _new = self._log_file
        _load = self._open_existing_file
        _reset = self._reset
        _exit = self.__exit
        self.buttons['new'] = B(bf, text='New file', command=_new)
        self.buttons['load'] = B(bf, text='Load', command=_load)
        self.buttons['reset'] = B(bf, text='Reset', command=_reset)
        self.buttons['exit'] = B(bf, fg='red', text='Exit', command=_exit)
        self.buttons['new'].pack(side='left', padx=5, pady=5)
        self.buttons['load'].pack(side='left', padx=5, pady=5)
        self.buttons['reset'].pack(side='left', padx=5, pady=5)
        self.buttons['exit'].pack(side='left', padx=5, pady=5)

    def __exit(self):
        """
        """
        self.caliper_ctrl.stop_caliper()
        self.destroy()

    def _log_file(self):
        """

        BULLSHIT!

        """
        save_as = tkFileDialog.asksaveasfilename
        file_name = save_as(**self.file_dialog_opts)
        if not file_name:
            return None
        # File clean-up?
        log_and_pickle = trapbox.log_and_pickle(file_name)
        trapbox.logfile, trapbox.pickle_name = log_and_pickle
        self.log_file.set('Current file: %s' % self.__get_log_name())
        """
        if self.caliper_ctrl.log_file_handle:
            if not self.caliper_ctrl.holding_measurements:
                self.caliper_ctrl._write_to_log()
            self.caliper_ctrl.log_file_handle.flush()
            self.caliper_ctrl.log_file_handle.close()
        self.caliper_ctrl.log_file_handle = save_as(**opts)
        self.log_file.set('Current file: %s' % self.__get_log_name())
        """

    def _open_existing_file(self):
        """

        In progress

        """
        ask_open = tkFileDialog.askopenfilename
        file_name = ask_open(**self.file_dialog_opts)
        if not file_name:
            return None
        #
        # Need to do file clean-up?
        #
        log_and_pickle = trapbox.log_and_pickle(file_name)
        trapbox.logfile, trapbox.pickle_name = log_and_pickle
        self.log_file.set('Current file: %s' % self.__get_log_name())
        #
        # TO DO:
        # Since we are opening an existing file, we need to tap into
        # the accompanying pickle to load all the goodies, so...
        #  * load pickle
        #  * self._set_area_factor()
        #  * self.sensors['A'].set(^1)
        #    ^1 seguramente accediendo ya a
        #       self.caliper_ctrl.measurements['A']

    def __get_log_name(self):
        """
        """
        try:
            tail = path_and_base(trapbox.logfile, 'one_dir_up')
        except AttributeError:
            tail = 'None'
        return tail

    def _reset(self):
        """
        """
        # Why reset the caliper? I don't understand what the hell I was
        # thinking
        #self.caliper_ctrl.stop_caliper()
        #time.sleep(1)
        #self.caliper_ctrl._reset()
        #
        # TODO:2009-06-09:damosurfer: Call a 'soft' reset from
        # mussel.py (as of yet unimplemented, see pertinent TODO in
        # mussel.py)
        for s in self.sensors:
            self.sensors[s].set('')
        self.boxes['factor']['state'] = 'normal'
        self.area_correction_factor.set('')
        self.area_factor_lock.set('Lock')

    def _grab_area_factor(self):
        """
        """
        if self.area_factor_lock.get() == 'Lock':
            try:
                factor = float(self.boxes['factor'].get())
            except:
                return None
            if factor:
                self.caliper_ctrl.config['area_factor'] = factor
                self.area_factor_lock.set('Unlock')
                self.boxes['factor']['state'] = 'disabled'
        else:
            self.caliper_ctrl.config['area_factor'] = 1
            self.area_factor_lock.set('Lock')
            self.boxes['factor']['state'] = 'normal'

